﻿#include "signuplogin.h"
#include "ui_signuplogin.h"
#include <QHostAddress>
#include <QMessageBox>
#include <QPainter>
#include <QFileDialog>
#include <QBuffer>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonParseError>
#include "stdshared.h"
#include "userinfo.h"
#include "mainface.h"

SignUpLogin::SignUpLogin(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::SignUpLogin),
    face(new MainFace)
{
    ui->setupUi(this);

    socket = new QTcpSocket(this);

    SetPhoto(QPixmap(":/img/photo.png"));
    setWindowIcon(QIcon(":/img/icon.png"));
    setWindowTitle("个人云存储系统");

    // 连接服务器
    socket->connectToHost(QHostAddress("192.168.157.128"), 8080);

    connect(socket,&QTcpSocket::connected,[]()
    {
            qDebug() << QStringLiteral("连接成功!\n");
    });

    // 准备读写
    connect(this->socket, &QTcpSocket::readyRead, this, &SignUpLogin::ReadData);

    connect(face, &MainFace::closeFace, [this]()
        {
            face->hide();
            this->show();
        });

    connect(this, &SignUpLogin::SetSocketAndName, face, &MainFace::GetSocketAndName);

    connect(ui->lineEdit_account, &QLineEdit::textChanged, [this]()
        {
            QString text = ui->lineEdit_account->text();
            if (UserInfo::getInstance()->GetPhoto(text).isNull())
            {
                SetPhoto(QPixmap(":/img/photo.png"));
            }
            else
            {
                ui->label_photo->setPixmap(UserInfo::getInstance()->GetPhoto(text));
            }
        });
}

SignUpLogin::~SignUpLogin()
{
    delete ui;
}

// 发送到服务器
void SignUpLogin::WriteToServer(const QJsonObject &obj)
{
    auto data = QJsonDocument(obj).toJson(); // 将QJsonObject包装成一个QJsonDocument对象,并将QJsonDocument转换为JSON格式的QByteArray
    size_t size =  data.size(); // 获取数据(data)的长度
    socket->write((char*)&size, sizeof(size_t)); // 将数据长度写入套接字(告诉接收方数据多长)
    socket->write(data); // 将Json数据写入套接字
}

// 处理json逻辑
void SignUpLogin::process(const QByteArray &data)
{
    auto obj = QJsonDocument::fromJson(data).object(); // 解析Json数据，允许访问Json数据中的各个字段
//    qDebug() << QStringLiteral("signup.cpp处理json逻辑:") << QJsonDocument(obj).toJson() << endl;

    if (obj["status"].toInt() == 1) // 如果Json数据中包含"result"字段且其值为0，则认为发生了错误
    {
        QMessageBox::information(this,"error",obj["reasson"].toString()); // 弹出一个信息框显示具体的错误消息("msg"字段)
        return;
    }

    if (obj["flag"] == 1) // 请求类型为"SIGNUP"时，表示需要注册
    {
        QMessageBox::information(this, QStringLiteral("提示"), QStringLiteral("注册成功!"));
        ui->lineEdit_account->clear();
        ui->lineEdit_passwd->clear();
        SetPhoto(QPixmap(":/img/photo.png"));
        return;
    }
    else if (obj["flag"] == 2) // 请求类型为"LOGIN"时，表示需要登录
    {
        QMessageBox::information(this, QStringLiteral("提示"), QStringLiteral("登录成功!")); // 弹出一个信息框显示具体的错误消息("msg"字段)
        QString photoBase64 = obj["photo"].toString();
        QByteArray photo = QByteArray::fromBase64(photoBase64.toUtf8());
        QPixmap pixmap;
        pixmap.loadFromData(photo);
        UserInfo::getInstance()->AddUser(ui->lineEdit_account->text(), pixmap);
        face->show();
        this->hide();
        emit SetSocketAndName(socket, ui->lineEdit_account->text());
        ui->lineEdit_account->clear();
        ui->lineEdit_passwd->clear();
        return;
    }
    else
    {
        face->process(data);
    }
}

// 设置头像
void SignUpLogin::SetPhoto(const QPixmap &photo)
{
    QPixmap circlePhoto(ui->label_photo->size());
    circlePhoto.fill(Qt::transparent); // 父窗口颜色
    QPainter painter(&circlePhoto); // 在图上作画
    painter.setBrush(photo.scaled(ui->label_photo->size())); // 将原图作为要作画的背景画到新的pixmap
    painter.setPen(Qt::NoPen); // 无边缘线
    painter.setRenderHint(QPainter::Antialiasing); // 设置线条光滑
    painter.drawEllipse(0, 0, ui->label_photo->width(), ui->label_photo->height());
    ui->label_photo->setPixmap(circlePhoto);
}

void SignUpLogin::mousePressEvent(QMouseEvent *e)
{
    if (e->button() == Qt::LeftButton)
    {
        auto pos = ui->label_photo->mapFromParent(e->pos()); // 父窗口的坐标转换成相对于子控件的坐标
        if (ui->label_photo->rect().contains(pos)) // photo矩形内
        {
            QString filepath = QFileDialog::getOpenFileName(this, QStringLiteral("获取一张图片"), "C:\\Users\\Default\\Desktop");
            if (filepath.size() == 0)
            {
                return;
            }
            SetPhoto(QPixmap(filepath));
        }
    }
}

void SignUpLogin::on_pushButton_signup_clicked()
{
    auto account = ui->lineEdit_account->text(); // 获取用户输入的账号
    auto passwd = ui->lineEdit_passwd->text(); // 获取用户输入的密码
    if (account == "" || passwd == "")
    {
        QMessageBox::information(this, QStringLiteral("提示"), QStringLiteral("请输入完整信息!"));
        return;
    }

    QPixmap photo = *(ui->label_photo->pixmap()); // 获取用户图像数据

    // QPixmap -> 二进制数据 QByteArray
    QByteArray imageInfo;
    QBuffer buffer(&imageInfo); // 缓冲区
    buffer.open(QIODevice::WriteOnly);
    photo.toImage().save(&buffer, "PNG"); // 以png的形式将图像数据写入缓冲区

    QJsonObject obj; // 构建Json对象
    obj["flag"] = REGISTER; // 请求类型为SIGNUP
    obj["name"] = account; // 用户的账号
    obj["passwd"] = passwd; // 用户的密码
    obj["photo"] = QString::fromUtf8(imageInfo.toBase64()); // 用户的图像
    WriteToServer(obj); // 发送到服务器
}

void SignUpLogin::on_pushButton_login_clicked()
{
    auto account = ui->lineEdit_account->text(); // 获取用户输入的账号
    auto passwd = ui->lineEdit_passwd->text(); // 获取用户输入的密码
    QJsonObject obj; // 构建Json对象
    obj["flag"] = LOGIN; // 请求类型为LOGIN
    obj["name"] = account; // 用户的账号
    obj["passwd"] = passwd; // 用户的密码
    WriteToServer(obj); // 发送到服务器
}

void SignUpLogin::ReadData()
{
    buffer += socket->readAll(); // 读取tcp缓冲区的所有数据
    while(buffer.size() >= sizeof(size_t)) // 读取的数据长度大于包头长度，说明有需要的数据
    {
        int size = 0;
        memcpy(&size, buffer.data(), sizeof(size_t)); // json包的大小
        if( buffer.size() < size + sizeof(size_t)) // buffer中的数据不够读一包json
        {
            return;
        }

        QByteArray data = buffer.mid(sizeof(size_t), size); // 一包json数据
        buffer.remove(0, size + sizeof(size_t)); // 删去已经读取过的数据
        process(data); // 处理json逻辑
    }
}
